package com.yans.views.display
{  
	import com.yans.GlobalAPICore;
	import com.yans.interfaces.IFish;
	
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	 
	
	/**
	 *	需求比较特别.在一个swf里..主场景放的不是序列资源.而是放着一个mc...而mc里面还有几个不同的动作跟状态.
	 * @author yans
	 * 	
	 */	
	public class SwfLoader implements IFish
	{
		//		private var _loader:Loader;
		private static const NAME:String = "yans.swfLoader";
		
		private static var _cache:Dictionary;			//缓存
		private static var _loaderList:Dictionary;	//加载器列表
		private static var _queue:Array;				//队列
		private static var _saveList:Array;
		
		private static var _AnalyzerList:Array;		//解析
		private static var _currentAnalyzer:SwfLoaderFrame;		//当前
		
		private var _path:String;
		private var _callBack:Array;		//回调
		private var loaderStatus:int;		//加载状态0:未加载, 1:正在加载, 2:加载过
		//		private var _cache:Dictionary;
		//		private var _dic:Dictionary
		private var _loaderD:Dictionary;
		//		private var _offset:Dictionary;
		private var _subName:String; 
		
		public var loaderInfo:LoaderInfo;
		public var appDomain:ApplicationDomain;
		
		public function SwfLoader(path:String) { 
			_path = path; 
			_callBack = [];
			_saveList = [];
			if(path == NAME) {
				appDomain = ApplicationDomain.currentDomain;
				loaderStatus = 2;
			}
		}
		
		public static function getInstance(path:String = NAME):SwfLoader {
			if(!_cache) _cache = new Dictionary;
			if(!_loaderList) _loaderList = new Dictionary;
			if(!_queue) _queue = [];
			if(!_AnalyzerList) _AnalyzerList = [];
			if(!_saveList) _saveList = [];
			if(_loaderList[path] != undefined) return _loaderList[path] as SwfLoader;
			
			if(!path) path = NAME;
			GlobalAPICore.timeManager.add(2000, saveFlashCache);
			_loaderList[path] = new SwfLoader(path);
			return _loaderList[path];
		}
		
		public function getMovie(callBack:Function, offset:Point = null, main:String = null, sub:String = null, frames:Array = null):void {
			if(!offset) offset = new Point;
			var key:SwfLoaderKey = new SwfLoaderKey(_path, main, sub, callBack, offset, frames);
			if(_cache[key.toKey()] != undefined) {
				//callBack(_cache[key.toKey()]);
				key.data = _cache[key.toKey()];
				callBack(key);
				loadNext();
			}
			else {
				GlobalAPICore.cacheManager.get(key.toKey(), function(byteArray:ByteArray):void { 
					if(byteArray) {
						callByKeyAndByteArray(key, byteArray);
					}
					else {
						load(key);
					}
				}, false);
			} 
		} 
		
		/**
		 *	创建一个等待
		 */		
		public function createMovie(callBack:Function, offset:Point, main:String, sub:String = null, frames:Array = null):void {
			var key:SwfLoaderKey = new SwfLoaderKey(_path, main, sub, callBack, offset, frames);
			key.setLoder(this);
			_queue.push(key);
		}
		
		
		public function loadNext():void {
			if(!_queue || _queue.length == 0) return;
			var key:SwfLoaderKey = _queue.pop() as SwfLoaderKey;
			key.loader.getMovie(key.callBack, key.offset, key.main, key.sub);
		}
		
		private function callByKeyAndByteArray(key:SwfLoaderKey, data:ByteArray):void {
			trace("#解析图源?", getTimer());
			var frame:BitmapFrameData = BitmapFrameData.byte2Frame(data);
			trace("#解析图源!", getTimer());
			_cache[key.toKey()] = frame;
			key.data = frame;
			//key.callBack(frame);
			key.callBack(key);
			loadNext();
		}
		
		
		private function load(key:SwfLoaderKey):void { 	 
			_callBack.push(key);
			if(loaderStatus == 1) {			//loading
			}
			else if(loaderStatus == 2) {	//loaded
				handleCallBack();
			}
			else {
				loaderStatus = 1;
				loadSwf(key.path);		//loaderInfo = 
			}			
		}
		
		private function handleCallBack():void {
			if(!_callBack || _callBack.length == 0) return;
			var key:SwfLoaderKey = _callBack.pop();
			while(key) { 
				try
				{
					if(_cache[key.toKey()] != undefined) {
						key.data = _cache[key.toKey()];
						//key.callBack(_cache[key.toKey()]);
						key.callBack(key);
					}
					else {
						var mc:MovieClip, cc:Class;
						
						if(key.main) {
							cc = appDomain.getDefinition(key.main) as Class;
							mc = new cc() as MovieClip;
							if(key.sub) {
								mc = mc[key.sub] as MovieClip;
							}
						}
						else if(!key.main && loaderInfo) {
							mc = loaderInfo.content as MovieClip;
							if(mc.totalFrames == 1) {
								if(!key.sub) {
									var len:int = mc.numChildren, child:MovieClip;
									while(len--) {
										child = mc.getChildAt(len) as MovieClip;
										if(child) {
											getMovie(key.callBack, key.offset, null, child.name, key.frames);
										}	
									}
									mc = null;
								}
								else {
									make(mc.getChildByName(key.sub) as MovieClip, key.clone(null, key.sub));
								} 
							}
						}
						if(mc) {
							make(mc, key);
						}
					}
				} 
				catch(error:Error) 
				{
					trace(error);
				}
				key = _callBack.pop();
			}
			loadNext();
		}
		
		private function loadSwf(path:String):LoaderInfo { 
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			loader.load(new URLRequest(path), new LoaderContext(false, new ApplicationDomain()));
			return loader.contentLoaderInfo;
		}
		
		private function onLoaderComplete(e:Event):void {
			loaderInfo = e.target as LoaderInfo;
			appDomain = loaderInfo.applicationDomain;
			loaderStatus = 2;
			handleCallBack();
			//			loaderInfo = e.target as LoaderInfo;
			//			var mc:MovieClip = loaderInfo.content as MovieClip;
			//			
			//			make(mc);
		}
		
		private function make(mc:MovieClip, key:SwfLoaderKey):void {
			
			if(mc.totalFrames > 0) {
				 
				var sFrame:SwfLoaderFrame = new SwfLoaderFrame();
				sFrame.offset = key.offset;
				sFrame.mc = mc;
				sFrame.index = 1;
				sFrame.call = key.callBack;
				sFrame.key = key.toKey();
				sFrame.frames = key.frames;
				sFrame.loaderKey = key;
				_AnalyzerList.push(sFrame);
				if(!GlobalAPICore.river.inRiver(this)) {
					GlobalAPICore.river.addFish(this);
				}
			} 
		}
		 
		private static function saveFlashCache():void {
			if(!_saveList || _saveList.length == 0) return;
			var dat:Array = _saveList.shift() as Array;
			var saveByteArr:ByteArray = dat[1].compress();
			GlobalAPICore.cacheManager.set(dat[0], saveByteArr, false);
		}
		
		private function onIOError(e:IOErrorEvent):void {
			var key:SwfLoaderKey = _callBack.pop();
			while(key) { 
				key.callBack(null);
				key = _callBack.pop();
			}
			loadNext()
			trace(e.text);
		}
		
		
		public function init(obj:Object):void { 
			
		}
		
		public function get code():int { 
			return 0;
		}
		
		public function dispose():void {
		}
		
		public function get target():Object {
			return null;
		}
		
		public function set target(obj:Object):void { 
		}
		
		public function swim(times:int, dt:Number=0.04):void
		{
			if(!_currentAnalyzer) {
				if(!_AnalyzerList || _AnalyzerList.length == 0) {
					GlobalAPICore.river.removeFish(this);
					return;
				}
				else {
					_currentAnalyzer = _AnalyzerList.splice(0, 1)[0] as SwfLoaderFrame;
					if(!_currentAnalyzer) {
						GlobalAPICore.river.removeFish(this);
						return;
					}
					_currentAnalyzer.index = 1;
				}
			}
			
			if(_cache[_currentAnalyzer.key] != undefined) {
				_currentAnalyzer.call(_cache[_currentAnalyzer.key]);
				_currentAnalyzer = null;
				return;
			}
			
			var mc:MovieClip = _currentAnalyzer.mc;
			var rect:Rectangle; 
			var tmpBD:BitmapData, sqr:int,  p:Point;
			var rx:int, ry:int;
			
			sqr = Math.ceil(Math.sqrt(mc.totalFrames));
			
			var endframe:int = Math.min(mc.totalFrames, _currentAnalyzer.index + 10);
			
			var matrix:Matrix = new Matrix(1, 0, 0, 1, 0, 0);
			var tx:Number;
			var ty:Number;
			
			for( ; _currentAnalyzer.index <= endframe; _currentAnalyzer.index++) {
				mc.gotoAndStop(_currentAnalyzer.index);
				rect = mc.getBounds(mc);
				if(rect.width == 0 || rect.height == 0) {
					rect = new Rectangle(1,1,1,1);
				}
				rx = Math.min(-rect.x, int.MAX_VALUE);
				ry = Math.min(-rect.y, int.MAX_VALUE);
				matrix.tx = rx;
				matrix.ty = ry; 
				_currentAnalyzer.offsetArr.push(new Point(int(rect.x), int(rect.y)));
				tmpBD = new BitmapData(rect.right - rect.x + 5, rect.bottom - rect.y + 7, true, 0);
				tmpBD.lock();
				tmpBD.draw(mc, matrix);
				
				if(tmpBD.width > _currentAnalyzer.maxWidth) _currentAnalyzer.maxWidth = tmpBD.width;
				if(tmpBD.height > _currentAnalyzer.maxHeight) _currentAnalyzer.maxHeight =tmpBD.height;
				
				_currentAnalyzer.tmpBDArr.push(tmpBD);
				tmpBD.unlock();
			}
			
			if(_currentAnalyzer.index >= mc.totalFrames) {
				try {
					_currentAnalyzer.bitmapData = new BitmapData(_currentAnalyzer.maxWidth * sqr, _currentAnalyzer.maxHeight * sqr, true, 0); 
					_currentAnalyzer.bitmapData.lock();
					for(var i:int = 0; i < _currentAnalyzer.tmpBDArr.length; i++) {
						tmpBD = _currentAnalyzer.tmpBDArr[i] as BitmapData;
						tmpBD.lock();
						p = new Point( int(i % sqr) * _currentAnalyzer.maxWidth, int(i / sqr) * _currentAnalyzer.maxHeight); 
						_currentAnalyzer.bitmapData.copyPixels(tmpBD, new Rectangle(0, 0, tmpBD.width, tmpBD.height), p);
						tmpBD.unlock();
						tmpBD.dispose();
					}
					_currentAnalyzer.bitmapData.unlock();
					var frame:BitmapFrameData = _currentAnalyzer.toFrame();
					frame.children = _currentAnalyzer.tmpBDArr;
					frame.frames = _currentAnalyzer.frames;
					
					//_currentAnalyzer.call(frame);
					_currentAnalyzer.loaderKey.data = frame;
					_currentAnalyzer.call(_currentAnalyzer.loaderKey);
					_cache[_currentAnalyzer.key] = frame;  
					_saveList.push([_currentAnalyzer.key, frame]);
					
					mc = null;
					trace("#", "完成key为" + _currentAnalyzer.key + "的加载，并已经清除完回调.");	
				} 
				catch(error:Error) {
					trace("#", error);
				}
				_currentAnalyzer = null;
			} 
		}
		
	}
}
